Chapter 12 RECORDS OUR FIRST LOOK AT A RECORD _________________________________________________________________ Ada has provision for two composite types, the =============== array, which we studied earlier, and the record, RECORD1.ADA which is the topic of this chapter. Examine the =============== program named RECORD1.ADA for our first example of a record. Lines 10 through 15 declare an Ada record, which actually only declares a type. The usual syntax for a type is used but when we come to the type definition itself, we begin with the reserved word record. The components of the record are then inserted, and the record type definition is terminated by the reserved words end record. A record can contain any desired components, the only requirement being that the component types must be declared prior to this definition, and the record type cannot be included as a component of itself. The key point to keep in mind about records is, whereas an array is composed of some number of like elements, the record is composed of some number of components that may be of different types. WHAT IS CONTAINED IN THE RECORD? _________________________________________________________________ It is impossible to declare an anonymous record type like you can do in Pascal. The record must be a named type prior to being used in a variable declaration. In this record, we have a variable named Month that is permitted to store any value from 1 through 12, obviously representing the months of the year. There are also Day and Year variables, each of which is different from Month since different constraints are placed upon each. After declaring the record type, we still have no actual variables, only a type, but in lines 17 through 19, we declare four variables of type DATE. Since the variables are of type DATE, each has three components, namely a Month, Day, and Year. Notice that two of the variables are initialized to the values given in parentheses in the order of the variable definitions. Month is therefore set to 5, Day to 25, and Year to 1982 for each of the two initialized variables, Today and Pay_Day. The initialization will be very clear after we discuss the program itself, so we will come back to it later. Page 12-1 Chapter 12 - Records HOW DO WE USE THE RECORDS? _________________________________________________________________ Since Independence_Day is actually a variable composed of three different variables, we need a way to tell the computer which subfield we are interested in using. We do this by combining the major variable name and the subfield with a dot as shown in lines 22 through 24. This is called the selected component notation in Ada. It should be clear to you that Independence_Day.Month is actually a single variable capable of storing an INTEGER type number as long as it is in the range of 1 through 12. The three elements of the record are three simple variables that can be used in a program wherever it is possible to use any other integer type variable. The three are grouped together for our convenience because they define a date which we call Independence_Day. The data could be stored in three simple variables and we could keep track of them in the way we usually handle data, but the record allows a more convenient grouping and a few additional operations. THE RECORD ASSIGNMENT _________________________________________________________________ There is one big advantage to using a record and it is illustrated in line 26 where all three values associated with the variable Independence_Day are assigned to the three corresponding components of the variable Birth_Day. If they were separate variables, they would have to be copied one at a time. The Day field of Pay_Day is assigned a new value in line 28 and the date contained in Independence_Day is displayed on the monitor for illustrative purposes. NAMED AND POSITIONAL AGGREGATES _________________________________________________________________ Line 38 has an example of assignment using a named aggregate in which the three fields are defined with their respective names and the pointing operator. It can be read as, "the variable named Day gets the value of 19, Month gets the value of 2, and so on". Since they are named, they are not required to be in the same order that they are in the record definition, but can be in any order. The real advantage to using the named aggregate notation is the fact that all elements are named and it is clear just what value is being assigned to each variable field. It should be pointed out that an aggregate is a group of data which may or may not be of the same type. Line 39 defines the three values of the record by simply giving the three values, but in this case, the three elements must be in the correct order so the compiler will be able to assign them to their correct subfields. This is called a positional aggregate. This is the kind of aggregate used to initialize the dates in line 19. Page 12-2 Chapter 12 - Records A MIXED AGGREGATE _________________________________________________________________ Line 40 illustrates use of a mixed aggregate in which some are defined by their position, and the rest are defined by their names. The positional definitions must come first, and after a named variable is given, the remainder must be named also. One point that must be remembered, all values must be mentioned, even if some of them will not be changed. This seems like a picky nuisance, but it greatly simplifies the compiler writer's job. Compile and run this program, and you will get the date of Independence Day displayed on your monitor. Be sure you understand this program, because understanding the next program requires that you thoroughly understand this one. It should be clear that whether you use the named, positional, or mixed notation, you are required to use the correct types for each of the parameters. A RECORD CONTAINING A RECORD _________________________________________________________________ Examine the file named RECORD2.ADA for an =============== example of a record declaration containing RECORD2.ADA another record within it. We declare the record =============== type DATE in exactly the same manner that we did in the last program, but we go on to declare another record type named PERSON. You will note that the new record is composed of four variables, one of the variables being of type DATE which contains three variables itself. We have thus declared a record that contains three simple variables and a variable record containing three more variables, leading to a total of six separate variables within this one record type. In line 22, we declare three variables, each composed of six simple variables, so we have 18 declared variables to work with in our example program. HOW TO USE THE COMPOSITE RECORD _________________________________________________________________ Lines 28 through 30 should pose no real problem for you since we are using knowledge gained during the last example program, but to assign the date requires another extension to our store of Ada knowledge. Notice that in addition to the name of the main variable Self, we must mention the Birth_Day variable which is part of it, and finally the subfield of the Birth_Day variable, Month in line 31. The variable name is therefore composed of the three names, "dotted" together resulting in the name of a unique simple variable. Once again, this is called the selected component notation. Lines 31 through 33 assign the remaining three fields of the variable Self some meaningful data. Line 36 assigns all six elements of the variable Self to the variable Mother in one simple statement. Line 37 is used to assign the values of only the three Page 12-3 Chapter 12 - Records components of Mother's Birth_Day to the three corresponding components of Father's Birth_Day. Since each subfield is actually only a simple variable, each one can be used in computations as illustrated in line 38 where Mother's Birth_Day Month is assigned the value which is 4 less than Self's Birth_Day Month. This is only done to illustrate that the simple variables can be used in any way you so desire, provided that you follow the rules of simple types. RENAMING A RECORD COMPONENT _________________________________________________________________ Line 24 illustrates how you can rename a component of a record in order to ease the problem of entering the dotted notation each time a field is used. In this case the simple name My_Birth_Year is a synonym for the extended naming required with all three components. Once again it must be pointed out that this only affects the compilation since it is only an additional name which can be used to refer to the variable. It must also be repeated that this facility should not be used except in those few case where it really adds to the program clarity. Correct use of the new name is illustrated in line 34. RECORD ASSIGNMENT AND COMPARISON _________________________________________________________________ As illustrated in lines 36 and 41, entire records can be assigned to other records of the same type, and entire records of the same type can be compared for equality or inequality. The records are equal only if every subfield of one record is equal to the corresponding subfield of the other. The other comparison operators are not available in Ada for records. Compile and run this program even though you will not get any output. Add some output statements yourself to see if you can get some of the data out to the monitor. AN ARRAY WITHIN A RECORD _________________________________________________________________ Examine the file named RECORD3.ADA and you will =============== find an array type declared in line 17 which is RECORD3.ADA then used in the record type PERSON. The =============== addition allows a variable of type PERSON to store four grades giving us a little additional flexibility over the last program. The method of assigning data to the new fields are illustrated in lines 38 through 41 and should require no additional comment, because you are already versed on how to use arrays. One rule must be mentioned here, you are not Page 12-4 Chapter 12 - Records allowed to declare an array with an anonymous type within a record, it must be named. Be sure to compile and run this program. AN ARRAY OF RECORDS _________________________________________________________________ Examine the file named RECORD4.ADA for an =============== example of an array of records. The types DATE RECORD4.ADA and PERSON are declared in a manner similar to =============== their declaration in RECORD2.ADA, but in line 26 we declare an array of 35 variables, each of type PERSON, so each is composed of six variable fields. In lines 44 through 50, we assign some nonsense data to each field of the 35 variables by using a loop. Finally, we assign nonsense data to a few of the variables to illustrate how it can be done in lines 52 through 57. You should have no problem understanding this program. Note that we could have assigned data to one of the records, the first for instance, then used it in a loop to assign values to all of the others by using a record assignment such as, "Class_Member(Index) := Class_Member(1);", and looping from 2 to 35. In a useful program, the data to be assigned will be coming from a file somewhere, as we would probably be filling a database. This is, in fact, the beginning of a very crude database. Another new construct is illustrated in lines 27 and 28 where we initialize the variable named Standard to the aggregate given. Note that, like the unnested record requirement, a nested record must be initialized with an aggregate which includes all values. Compile and run this program to assure yourself that it really will compile and run. PROGRAMMING EXERCISES _________________________________________________________________ 1. Rewrite RECORD4.ADA and change the initialization aggregate for Standard from a positional aggregate to a named aggregate. 2. Rewrite RECORD1.ADA to utilize the enumerated type for the month field as used in RECORD3.ADA. Note that you will need to instantiate a copy of the package named Enumerated_IO to display the month name. Page 12-5